// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/cast/net/rtp/rtp_packet_builder.h"

#include "base/big_endian.h"
#include "base/logging.h"

namespace media {
namespace cast {

    RtpPacketBuilder::RtpPacketBuilder()
        : is_key_(false)
        , frame_id_(0)
        , packet_id_(0)
        , max_packet_id_(0)
        , reference_frame_id_(0)
        , timestamp_(0)
        , sequence_number_(0)
        , marker_(false)
        , payload_type_(0)
        , ssrc_(0)
    {
    }

    void RtpPacketBuilder::SetKeyFrame(bool is_key) { is_key_ = is_key; }

    void RtpPacketBuilder::SetFrameIds(uint32_t frame_id,
        uint32_t reference_frame_id)
    {
        frame_id_ = frame_id;
        reference_frame_id_ = reference_frame_id;
    }

    void RtpPacketBuilder::SetPacketId(uint16_t packet_id)
    {
        packet_id_ = packet_id;
    }

    void RtpPacketBuilder::SetMaxPacketId(uint16_t max_packet_id)
    {
        max_packet_id_ = max_packet_id;
    }

    void RtpPacketBuilder::SetTimestamp(uint32_t timestamp)
    {
        timestamp_ = timestamp;
    }

    void RtpPacketBuilder::SetSequenceNumber(uint16_t sequence_number)
    {
        sequence_number_ = sequence_number;
    }

    void RtpPacketBuilder::SetMarkerBit(bool marker) { marker_ = marker; }

    void RtpPacketBuilder::SetPayloadType(int payload_type)
    {
        payload_type_ = payload_type;
    }

    void RtpPacketBuilder::SetSsrc(uint32_t ssrc)
    {
        ssrc_ = ssrc;
    }

    void RtpPacketBuilder::BuildHeader(uint8_t* data, uint32_t data_length)
    {
        BuildCommonHeader(data, data_length);
        BuildCastHeader(data + kRtpHeaderLength, data_length - kRtpHeaderLength);
    }

    void RtpPacketBuilder::BuildCastHeader(uint8_t* data, uint32_t data_length)
    {
        // Build header.
        DCHECK_LE(kCastHeaderLength, data_length);
        // Set the first 7 bytes to 0.
        memset(data, 0, kCastHeaderLength);
        base::BigEndianWriter big_endian_writer(reinterpret_cast<char*>(data), 56);
        const bool includes_specific_frame_reference = (is_key_ && (reference_frame_id_ != frame_id_)) || (!is_key_ && (reference_frame_id_ != (frame_id_ - 1)));
        big_endian_writer.WriteU8((is_key_ ? 0x80 : 0) | (includes_specific_frame_reference ? 0x40 : 0));
        big_endian_writer.WriteU8(frame_id_);
        big_endian_writer.WriteU16(packet_id_);
        big_endian_writer.WriteU16(max_packet_id_);
        if (includes_specific_frame_reference) {
            big_endian_writer.WriteU8(reference_frame_id_);
        }
    }

    void RtpPacketBuilder::BuildCommonHeader(uint8_t* data, uint32_t data_length)
    {
        DCHECK_LE(kRtpHeaderLength, data_length);
        base::BigEndianWriter big_endian_writer(reinterpret_cast<char*>(data), 96);
        big_endian_writer.WriteU8(0x80);
        big_endian_writer.WriteU8(payload_type_ | (marker_ ? kRtpMarkerBitMask : 0));
        big_endian_writer.WriteU16(sequence_number_);
        big_endian_writer.WriteU32(timestamp_);
        big_endian_writer.WriteU32(ssrc_);
    }

} // namespace cast
} // namespace media
